/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package w40k.roster2client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.StringWriter;
import java.io.DataOutputStream;
import java.io.PrintWriter;
import w40k.data.Armylist;
import w40k.data.ActivityState;
import w40k.data.Slot;
import w40k.data.Unit;
import w40k.data.Subunit;
import w40k.data.Equipment;
import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
/**
 *
 * @author User
 */
public class sheetServlet extends HttpServlet 
{
    private String serviceBase = "";//http://localhost:8084/roster2/rosterService/";
    private final String armyInitial = "army/initial";
    private final String unitVariant = "unit/variant";
    private final String unitInitial = "unit/initial";
    private final String unitDeleted = "unit/finalised";
    private Armylist internal;
    
    private void evaluateValidityLocal()
    {
        boolean isValid = true;
        for (Slot s: internal.getSlot())
            isValid = isValid && s.getValid();
        internal.setValid(isValid);
    }
    
    private String asString( JAXBContext pContext, Object pObject) throws JAXBException 
    {
        StringWriter sw = new StringWriter();
        
        Marshaller marshaller = pContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        marshaller.marshal(pObject, sw);
        
        return sw.toString();
    }
          	  
    private DataInputStream postRequest(String httpMethod, String content, String contentType) throws MalformedURLException,IOException
    {
        URL                 url;
        URLConnection   urlConn;
        DataOutputStream    printout;
        DataInputStream     input;
        // URL of REST service method
        url = new URL (serviceBase + httpMethod);
        // URL connection channel.
        urlConn = url.openConnection();
        // Let the run-time system (RTS) know that we want input.
        urlConn.setDoInput (true);
        // Let the RTS know that we want to do output.
        urlConn.setDoOutput (true);
        // No caching, we want the real thing.
        urlConn.setUseCaches (false);
        // Specify the content type.
        urlConn.setRequestProperty
        ("Content-Type", contentType);
        // Send POST output.
        printout = new DataOutputStream (urlConn.getOutputStream ());
        //String content =
        //"name=" + URLEncoder.encode ("Buford Early") +
        //"&email=" + URLEncoder.encode ("buford@known-space.com");
        printout.writeBytes (content);
        printout.flush ();
        printout.close ();
        // Get response data.
        input = new DataInputStream (urlConn.getInputStream ());
        return input;
    }
    
    private void processAddUnitStart(HttpServletRequest request,JAXBContext jc, Unmarshaller u)
            throws JAXBException, IOException 
    {
        Slot aSlot = null;
        for(Slot s: internal.getSlot())
        {
            if(request.getParameterMap().containsKey(s.getType()))
            {
                s.setState(ActivityState.ACTIVE);
                s.Freeze(false);
                aSlot = s;
                //break;
            }
            else
                s.Freeze(true);
        }
        DataInputStream restResponse = postRequest(unitVariant, asString(jc,internal),"application/xml");
        aSlot.setChoice(((Slot)u.unmarshal(restResponse)).getChoice());
        restResponse.close();
    }
    
    private void processDeleteUnit(String key,JAXBContext jc, Unmarshaller u)
            throws JAXBException, IOException 
    {
        StringTokenizer st = new StringTokenizer(key,"_");
        String sName = st.nextToken();
        for(Slot s: internal.getSlot())
        {
            if(s.getType().equals(sName))
            {
                s.getUnit().remove(Integer.parseInt(st.nextToken()));
                s.setState(ActivityState.MUTABLE);
                break;
            }
        }
        DataInputStream restResponse = postRequest(unitDeleted, asString(jc,internal),"application/xml");
        internal = (Armylist)u.unmarshal(restResponse);
        restResponse.close();
        evaluateValidityLocal();
    }
    
    private void processCancelUnit()
    {
        for(Slot s: internal.getSlot())
        {
            s.Unfreeze(true);
        }
    }

    private void processAddUnitFinish(HttpServletRequest request, JAXBContext jc, Unmarshaller u)
            throws JAXBException, IOException 
    {
        Slot aSlot = null;
        for(Slot s: internal.getSlot())
        {
            if(s.getState() == ActivityState.ACTIVE)
            {
                
                aSlot = s;
                //break;
            }
            s.Unfreeze(true);
        }
        String req = internal.getArmy()+":"+request.getParameterMap().get("unit")[0] + ":" + aSlot.getType() + ":" + (aSlot.getUnit().size() + 1);
        DataInputStream restResponse = postRequest(unitInitial, req,"text/plain");
        aSlot.setChoice(null);
        Unit uRes = (Unit)u.unmarshal(restResponse);
        if (uRes.getState() == ActivityState.FIXED)
            aSlot.setState(ActivityState.FIXED);
        if (!aSlot.getValid() && uRes.getState() != ActivityState.FROZEN)
        {
            aSlot.setValid(true);
            evaluateValidityLocal();
        }
        if (uRes.getSubunit().get(0).getState() == ActivityState.FIXED)
            uRes.setState(ActivityState.FIXED);
        else
            uRes.setState(ActivityState.MUTABLE);
        aSlot.getUnit().add(aSlot.getUnit().size(),uRes);
        restResponse.close();
    }
    
    private void processQChoiceChangeActivity(String key, boolean activate)
    {
        StringTokenizer st = new StringTokenizer(key,"_");
        String sName = st.nextToken();
        for(Slot s: internal.getSlot())
        {
            if(activate)
                s.Freeze(true);
            else
                s.Unfreeze(true);
            if(s.getType().equals(sName))
            {
                int uNumber = Integer.parseInt(st.nextToken());
                for(int i = 0; i < s.getUnit().size(); i++)
                {
                    //if (s.getUnit().get(i).getState() != ActivityState.FIXED)
                    //    s.getUnit().get(i).setState(activate?ActivityState.FROZEN:ActivityState.MUTABLE);                    
                    if (i == uNumber)
                    {
                        int suNumber = Integer.parseInt(st.nextToken());
                        for (int j = 0; j < s.getUnit().get(i).getSubunit().size(); j++)
                        {
                            if (j == suNumber)
                            {
                                if (activate)
                                    s.getUnit().get(uNumber).getSubunit().get(suNumber).setState(ActivityState.ACTIVE);
                            }
                        }
                            //(activate?(()?:ActivityState.FROZEN):ActivityState.MUTABLE);
                    }

                }
                //s.setState(ActivityState.MUTABLE);
                //break;
            }
        }
    }
    
    private void processQChoiceAccept(HttpServletRequest request, String key)
    {
        StringTokenizer st = new StringTokenizer(key,"_");
        String sName = st.nextToken();
        int chosen = Integer.parseInt(request.getParameterMap().get("qchoice")[0]);
        for(Slot s: internal.getSlot())
        {
            if(s.getType().equals(sName))
            {
                Subunit cur = s.getUnit().get(Integer.parseInt(st.nextToken())).getSubunit().get(Integer.parseInt(st.nextToken()));
                cur.setQuantity(chosen);
                cur.setState(ActivityState.MUTABLE);
                //s.setState(ActivityState.);
                break;
            }
        }
    }
    
    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException 
    {
//        w40k.roster.service.RosterGeneratorService service = new w40k.roster.service.RosterGeneratorService();
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try
        {
            JAXBContext jc = JAXBContext.newInstance ("w40k.data");
            Unmarshaller u = jc.createUnmarshaller();
            String race = request.getParameter("race");
            if(race != null)
            {
                //out.println("<h1>" + race + "</h1>");
                try
                {
                    DataInputStream restResponse = postRequest(armyInitial,race,"text/plain");
                    internal = (Armylist)u.unmarshal(restResponse);
                    restResponse.close();
                }
                catch (Exception ex) 
                {
                // TODO handle custom exceptions here
                    ex.printStackTrace(out);
                }
                //internal = service.getInitial(race);
            }
            else
            {
                //boolean slotAdded = false;
                for(String key:request.getParameterMap().keySet())
                {
                    String param = request.getParameterMap().get(key)[0];
                    if(param.equals("addUnit"))
                    {
                        processAddUnitStart(request,jc,u);
                    }
                    if(param.equals("cancelUnit"))
                    {
                        processCancelUnit();
                    }
                    if(param.equals("confirmUnit"))
                    {
                        processAddUnitFinish(request,jc,u);
                        internal.getCost();
                    }
                    if(param.equals("deleteUnit"))
                    {
                        processDeleteUnit(key,jc,u);
                        internal.getCost();
                    }
                    if(param.equals("subUnitQChange"))
                    {
                        processQChoiceChangeActivity(key,true);
                    }
                    if(param.equals("subUnitQChangeDecline"))
                    {
                        processQChoiceChangeActivity(key,false);
                    }
                    if(param.equals("subUnitQChangeApprove"))
                    {
                        processQChoiceChangeActivity(key,false);
                        processQChoiceAccept(request,key);
                        internal.getCost();
                    }                    
                }
            }
            new pageGenerator(internal).generatePage(out);
        }
        catch(Exception e)
        {
            e.printStackTrace(out);
        }
    }
    
    @Override
    public void init() throws ServletException
    {
        try
        {
            ClassLoader cl = this.getClass().getClassLoader();
            BufferedReader br = new BufferedReader(new InputStreamReader(cl.getResourceAsStream("serviceLocation.yml")));
            String restUrl = "";
            while("".equals(restUrl))
            {
                String line = br.readLine();
                if (line == null) break;
                if (line.trim().startsWith("location:"))
                    restUrl = line.substring(9).trim();
            }
            serviceBase = restUrl;
        }
        catch (IOException ex)
        {
            throw new ServletException("Unable to read service location from serviceLocation.yml.",ex);
        }
    }
    
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
